﻿/*----------------------------------------------------------------
        // Copyright (C) 2016 Rookey
        // 版权所有
        // 开发者：Rookey
        // Email：rookey@yeah.net
        // QQ：3319549098
//----------------------------------------------------------------*/

using Rookey.Frame.Common;
using Rookey.Frame.Operate.Base;
using Rookey.Frame.Operate.Base.TempModel;
using Rookey.Frame.Operate.Base.Extension;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using Rookey.Frame.Model.Bpm;
using Rookey.Frame.Controllers.Other;
using System.Web;
using Rookey.Frame.Operate.Base.OperateHandle;
using Rookey.Frame.Common.Model;
using Rookey.Frame.Common.PubDefine;
using Rookey.Frame.Model.EnumSpace;
using Rookey.Frame.Base;
using Rookey.Frame.Model.Sys;
using System.Threading.Tasks;

namespace Rookey.Frame.Controllers
{
    /// <summary>
    /// 工作流处理控制器
    /// </summary>
    public class BpmController : BaseController
    {
        #region 构造函数

        private HttpRequestBase _Request = null; //请求对象

        /// <summary>
        /// 无参构造函数
        /// </summary>
        public BpmController()
        {
            _Request = Request;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="request">请求对象</param>
        public BpmController(HttpRequestBase request)
        {
            _Request = request;
        }

        #endregion

        #region 页面定义

        /// <summary>
        /// 流程设计页面
        /// </summary>
        /// <returns></returns>
        public ActionResult FlowDesign()
        {
            return View();
        }

        /// <summary>
        /// 流程画布
        /// </summary>
        /// <returns></returns>
        public ActionResult FlowCanvas()
        {
            return View();
        }

        /// <summary>
        /// 流程节点参数设置
        /// </summary>
        /// <returns></returns>
        public ActionResult NodeParamSet()
        {
            return View();
        }

        /// <summary>
        /// 流程连线参数设置
        /// </summary>
        /// <returns></returns>
        public ActionResult LineParamSet()
        {
            return View();
        }

        #endregion

        #region 数据处理

        #region 流程设计

        /// <summary>
        /// 获取流程分类树，包括流程分类下的流程
        /// </summary>
        /// <returns></returns>
        public ActionResult GetFlowClassTree()
        {
            Guid parentId = _Request["parentId"].ObjToGuid(); //指定根节点
            bool noRoot = _Request["noRoot"].ObjToInt() == 1; //是否去掉根结点
            TreeNode node = BpmOperate.LoadFlowClassTree(parentId);
            if (noRoot && node != null && node.id == Guid.Empty.ToString())
            {
                return Json(node.children.ToJson().Content, JsonRequestBehavior.AllowGet);
            }
            return Json(node, JsonRequestBehavior.AllowGet);
        }

        /// <summary>
        /// 更新流程图
        /// </summary>
        /// <returns></returns>
        public ActionResult UpdateWorkflowChart()
        {
            string workflowJson = HttpUtility.UrlDecode(MySecurity.DecodeBase64(_Request["workflowJson"].ObjToStr()), Encoding.UTF8);
            Bpm_WorkFlow workFlow = JsonHelper.Deserialize<Bpm_WorkFlow>(workflowJson);
            if (workFlow == null)
                return Json(new ReturnResult() { Success = false, Message = "流程对象反序列化失败！" });
            Guid moduleId = BpmOperate.GetWorkflowModuleId(workFlow.Id);
            if (moduleId == Guid.Empty)
                return Json(new ReturnResult() { Success = false, Message = "流程没有设置关联模块！" });
            string errMsg = string.Empty;
            //保存流程节点
            //先删除节点
            CommonOperate.DeleteRecordsByExpression<Bpm_WorkNode>(x => x.Bpm_WorkFlowId == workFlow.Id, out errMsg);
            //删除节点审批按钮
            CommonOperate.DeleteRecordsByExpression<Bpm_NodeBtnConfig>(x => x.Bpm_WorkFlowId == workFlow.Id, out errMsg);
            if (workFlow.WorkNodes != null && workFlow.WorkNodes.Count > 0)
            {
                Sys_Form defaultForm = SystemOperate.GetDefaultForm(moduleId);
                //保存节点和节点审批按钮
                foreach (Bpm_WorkNode workNode in workFlow.WorkNodes)
                {
                    workNode.DisplayName = workNode.Name;
                    workNode.Code = string.Format("WN{0}", DateTime.Now.ToString("yyyyMMddHHmmssfff"));
                    workNode.Bpm_WorkFlowId = workFlow.Id;
                    if (workNode.WorkNodeTypeOfEnum != WorkNodeTypeEnum.Start && workNode.WorkNodeTypeOfEnum != WorkNodeTypeEnum.End &&
                        workNode.Sys_FormId == Guid.Empty && string.IsNullOrEmpty(workNode.FormUrl) && defaultForm != null)
                    {
                        workNode.Sys_FormId = defaultForm.Id;
                    }
                    Guid nodeId = CommonOperate.OperateRecord<Bpm_WorkNode>(workNode, ModelRecordOperateType.Add, out errMsg, null, false);
                    if (nodeId != Guid.Empty && workNode.BtnConfigs != null && workNode.BtnConfigs.Count > 0)
                    {
                        workNode.Id = nodeId;
                        workNode.BtnConfigs.ForEach(x =>
                        {
                            x.Code = string.Format("NBC{0}", DateTime.Now.ToString("yyyyMMddHHmmssfff"));
                            x.Bpm_WorkFlowId = workFlow.Id;
                            x.Bpm_WorkNodeId = nodeId;
                        });
                        CommonOperate.OperateRecords<Bpm_NodeBtnConfig>(workNode.BtnConfigs, ModelRecordOperateType.Add, out errMsg, false);
                    }
                }
            }
            //保存流程连线
            //先删除连线
            CommonOperate.DeleteRecordsByExpression<Bpm_WorkLine>(x => x.Bpm_WorkFlowId == workFlow.Id, out errMsg);
            if (workFlow.WorkLines != null && workFlow.WorkLines.Count > 0)
            {
                foreach (Bpm_WorkLine workLine in workFlow.WorkLines)
                {
                    Bpm_WorkNode startNode = workFlow.WorkNodes.Where(x => x.TagId == workLine.FromTagId).FirstOrDefault();
                    Bpm_WorkNode endNode = workFlow.WorkNodes.Where(x => x.TagId == workLine.ToTagId).FirstOrDefault();
                    workLine.Bpm_WorkFlowId = workFlow.Id;
                    workLine.Bpm_WorkNodeStartId = startNode.Id;
                    workLine.Bpm_WorkNodeEndId = endNode.Id;
                    workLine.Code = string.Format("WL{0}", DateTime.Now.ToString("yyyyMMddHHmmssfff"));
                    Guid lineId = CommonOperate.OperateRecord<Bpm_WorkLine>(workLine, ModelRecordOperateType.Add, out errMsg, null, false);
                }
            }
            return Json(new ReturnResult() { Success = true, Message = string.Empty });
        }

        /// <summary>
        /// 加载流程图
        /// </summary>
        /// <returns></returns>
        public ActionResult LoadWorkflowChart()
        {
            Guid workflowId = _Request["workflowId"].ObjToGuid();
            Bpm_WorkFlow workflow = BpmOperate.GetWorkflow(workflowId);
            if (workflow != null)
            {
                Dictionary<string, object> dicNodes = null;
                Dictionary<string, object> dicLines = null;
                Dictionary<string, object> nodeParams = null;
                Dictionary<string, object> lineParams = null;
                List<Bpm_WorkNode> workNodes = BpmOperate.GetWorkNodesOfFlow(workflowId);
                List<Bpm_WorkLine> workLines = BpmOperate.GetWorkLinesOfFlow(workflowId);
                if (workNodes.Count > 0)
                {
                    dicNodes = new Dictionary<string, object>();
                    nodeParams = new Dictionary<string, object>();
                    foreach (Bpm_WorkNode tempNode in workNodes)
                    {
                        string nodeType = "task round";
                        switch (tempNode.WorkNodeTypeOfEnum)
                        {
                            case WorkNodeTypeEnum.Start:
                                nodeType = "start round";
                                break;
                            case WorkNodeTypeEnum.End:
                                nodeType = "end round";
                                break;
                            default:
                                nodeType = "task round";
                                break;
                        }
                        dicNodes.Add(tempNode.TagId, new { type = nodeType, name = tempNode.Name, alt = true, width = tempNode.Width, height = tempNode.Height, left = tempNode.Left, top = tempNode.Top });
                        if (tempNode.WorkNodeTypeOfEnum != WorkNodeTypeEnum.Start && tempNode.WorkNodeTypeOfEnum != WorkNodeTypeEnum.End)
                        {
                            tempNode.BtnConfigs = BpmOperate.GetAllApprovalBtnConfigs(x => x.Bpm_WorkFlowId == workflowId && x.Bpm_WorkNodeId == tempNode.Id);
                            nodeParams.Add(tempNode.TagId, new { Name = tempNode.Name, Sys_FormId = tempNode.Sys_FormId, FormUrl = tempNode.FormUrl, HandlerType = tempNode.HandlerType, HandleRange = tempNode.HandleRange, HandleStrategy = tempNode.HandleStrategy, FormFieldName = tempNode.FormFieldName, BackType = tempNode.BackType, AutoJumpRule = tempNode.AutoJumpRule, Bpm_WorkFlowId = tempNode.Bpm_WorkFlowId, TagId = tempNode.TagId, BtnConfigs = tempNode.BtnConfigs });
                        }
                    }
                }
                if (workLines.Count > 0)
                {
                    dicLines = new Dictionary<string, object>();
                    lineParams = new Dictionary<string, object>();
                    foreach (Bpm_WorkLine tempLine in workLines)
                    {
                        dicLines.Add(tempLine.TagId, new { type = "sl", name = tempLine.Note, M = tempLine.M, from = tempLine.FromTagId, to = tempLine.ToTagId });
                        lineParams.Add(tempLine.TagId, new { Note = tempLine.Note, FormCondition = tempLine.FormCondition, DutyCondition = tempLine.DutyCondition, DeptCondition = tempLine.DeptCondition, SqlCondition = tempLine.SqlCondition, IsCustomerCondition = tempLine.IsCustomerCondition });
                    }
                }
                return Json(new { FlowData = new { title = workflow.Name, nodes = dicNodes, lines = dicLines, initNum = dicNodes.Count + dicLines.Count }, NodeParams = nodeParams, LineParams = lineParams }, JsonRequestBehavior.AllowGet);
            }
            return Json(null, JsonRequestBehavior.AllowGet);
        }

        /// <summary>
        /// 获取节点表单
        /// </summary>
        /// <returns></returns>
        public ActionResult GetNodeForms()
        {
            Guid workflowId = _Request["workflowId"].ObjToGuid(); //流程ID
            string tagId = _Request["tagId"].ObjToStr(); //节点tagId
            Bpm_WorkFlow workflow = BpmOperate.GetWorkflow(workflowId);
            if (workflow != null && workflow.Sys_ModuleId.HasValue && workflow.Sys_ModuleId.Value != Guid.Empty)
            {
                List<Sys_Form> forms = SystemOperate.GetModuleForms(workflow.Sys_ModuleId.Value);
                return Json(forms);
            }
            return Json(null);
        }

        /// <summary>
        /// 加载处理者字段
        /// </summary>
        /// <returns></returns>
        public ActionResult LoadHandlerFields()
        {
            Guid formId = _Request["formId"].ObjToGuid(); //表单ID
            List<Sys_FormField> formFields = SystemOperate.GetFormField(formId);
            if (formFields.Count > 0)
            {
                List<Guid> sysFieldIds = formFields.Where(x => x.Sys_FieldId.HasValue && x.Sys_FieldId.Value != Guid.Empty).Select(x => x.Sys_FieldId.Value).ToList();
                List<Sys_Field> fields = SystemOperate.GetFields(x => sysFieldIds.Contains(x.Id)).Where(x => x.ForeignModuleName == "员工管理").ToList();
                return Json(fields, JsonRequestBehavior.AllowGet);
            }
            return Json(null, JsonRequestBehavior.AllowGet);
        }

        #endregion

        #region 流程操作

        /// <summary>
        /// 发起流程
        /// </summary>
        /// <param name="moduleId">模块ID</param>
        /// <param name="id">记录ID</param>
        /// <returns></returns>
        public ActionResult StartProcess(Guid moduleId, Guid id)
        {
            UserInfo currUser = CurrentUser;
            string errMsg = BpmOperate.StartProcess(moduleId, id, currUser);
            Task.Factory.StartNew(() =>
            {
                LogOperate.AddOperateLog(currUser, SystemOperate.GetModuleNameById(moduleId), BpmOperate.GetFlowOpTypeDes(WorkActionEnum.Starting), JsonHelper.Serialize(new { RecordId = id }), string.IsNullOrEmpty(errMsg), errMsg);
            });
            return Json(new SaveDataReturnResult() { Success = string.IsNullOrEmpty(errMsg), Message = errMsg, RecordId = id });
        }

        /// <summary>
        /// 审批流程
        /// </summary>
        /// <param name="toDoTaskId">待办任务ID</param>
        /// <param name="approvalOpinions">处理意见</param>
        /// <param name="workAction">动作</param>
        /// <param name="returnNodeId">退回时退回结点</param>
        /// <param name="directHandler">指派时的被指派人</param>
        /// <returns></returns>
        public ActionResult ApprovalProcess(Guid toDoTaskId, string approvalOpinions, WorkActionEnum workAction, Guid? returnNodeId = null, Guid? directHandler = null)
        {
            UserInfo currUser = CurrentUser;
            string errMsg = BpmOperate.ApproveProcess(toDoTaskId, approvalOpinions, currUser, workAction, returnNodeId, directHandler);
            Task.Factory.StartNew(() =>
            {
                Guid moduleId = Guid.Empty;
                Guid recordId = Guid.Empty;
                BpmOperate.GetModuleIdAndRecordIdByTodoId(toDoTaskId, out moduleId, out recordId);
                LogOperate.AddOperateLog(currUser, SystemOperate.GetModuleNameById(moduleId), BpmOperate.GetFlowOpTypeDes(workAction), JsonHelper.Serialize(new { RecordId = recordId }), string.IsNullOrEmpty(errMsg), errMsg);
            });
            return Json(new ReturnResult() { Success = string.IsNullOrEmpty(errMsg), Message = errMsg });
        }

        /// <summary>
        /// 处理待办流程，包括同意、拒绝等操作
        /// </summary>
        /// <param name="toDoTaskId">待办任务ID</param>
        /// <param name="approvalOpinions">处理意见</param>
        /// <param name="flowBtnId">操作按钮ID</param>
        /// <param name="returnNodeId">退回时退回结点</param>
        /// <param name="directHandler">指派时的被指派人</param>
        /// <returns></returns>
        public ActionResult HandleOpProcess(Guid toDoTaskId, string approvalOpinions, Guid flowBtnId, Guid? returnNodeId = null, Guid? directHandler = null)
        {
            WorkActionEnum workAction = WorkActionEnum.NoAction;
            Bpm_FlowBtn flowBtn = BpmOperate.GetAllWorkButtons(x => x.Id == flowBtnId).FirstOrDefault();
            if (flowBtn != null)
            {
                switch (flowBtn.ButtonTypeOfEnum)
                {
                    case FlowButtonTypeEnum.AgreeBtn:
                        workAction = WorkActionEnum.Approving;
                        break;
                    case FlowButtonTypeEnum.BackBtn:
                        workAction = WorkActionEnum.Returning;
                        break;
                    case FlowButtonTypeEnum.RejectBtn:
                        workAction = WorkActionEnum.Refusing;
                        break;
                    case FlowButtonTypeEnum.AssignBtn:
                        workAction = WorkActionEnum.Directing;
                        break;
                }
            }
            else if (toDoTaskId == flowBtnId) //回退重新提交
            {
                workAction = WorkActionEnum.ReStarting;
            }
            return ApprovalProcess(toDoTaskId, approvalOpinions, workAction, returnNodeId, directHandler);
        }

        /// <summary>
        /// 加载回退结点
        /// </summary>
        /// <param name="toDoTaskId">待办ID</param>
        /// <returns></returns>
        public ActionResult LoadBackNode(Guid toDoTaskId)
        {
            List<Bpm_WorkNode> backNodes = BpmOperate.GetBackNodes(toDoTaskId);
            StringBuilder sb = new StringBuilder();
            sb.Append("<div style=\"padding-top:20px;padding-left:30px\">");
            sb.Append("<select id=\"backNodes\" name=\"backNodes\" class=\"easyui-combobox\" style=\"width:200px;\">");
            foreach (Bpm_WorkNode node in backNodes)
            {
                sb.AppendFormat("<option value=\"{0}\">{1}</option>", node.Id, node.Name);
            }
            sb.Append("</select>");
            sb.Append("</div>");
            return Json(new { html = sb.ToString() }, JsonRequestBehavior.AllowGet);
        }

        #endregion

        #endregion
    }

    /// <summary>
    /// 异步控制器
    /// </summary>
    public class BpmAsyncController : AsyncBaseController
    {
        #region 流程设计

        /// <summary>
        /// 获取流程分类树，包括流程分类下的流程
        /// </summary>
        /// <returns></returns>
        public Task<ActionResult> GetFlowClassTreeAsync()
        {
            return Task.Factory.StartNew(() =>
            {
                return new BpmController(Request).GetFlowClassTree();
            }).ContinueWith<ActionResult>(task =>
            {
                return task.Result;
            });
        }

        /// <summary>
        /// 更新流程图
        /// </summary>
        /// <returns></returns>
        public Task<ActionResult> UpdateWorkflowChartAsync()
        {
            return Task.Factory.StartNew(() =>
            {
                return new BpmController(Request).UpdateWorkflowChart();
            }).ContinueWith<ActionResult>(task =>
            {
                return task.Result;
            });
        }

        /// <summary>
        /// 加载流程图
        /// </summary>
        /// <returns></returns>
        public Task<ActionResult> LoadWorkflowChartAsync()
        {
            return Task.Factory.StartNew(() =>
            {
                return new BpmController(Request).LoadWorkflowChart();
            }).ContinueWith<ActionResult>(task =>
            {
                return task.Result;
            });
        }

        /// <summary>
        /// 获取节点表单
        /// </summary>
        /// <returns></returns>
        public Task<ActionResult> GetNodeFormsAsync()
        {
            return Task.Factory.StartNew(() =>
            {
                return new BpmController(Request).GetNodeForms();
            }).ContinueWith<ActionResult>(task =>
            {
                return task.Result;
            });
        }

        /// <summary>
        /// 加载处理者字段
        /// </summary>
        /// <returns></returns>
        public Task<ActionResult> LoadHandlerFieldsAsync()
        {
            return Task.Factory.StartNew(() =>
            {
                return new BpmController(Request).LoadHandlerFields();
            }).ContinueWith<ActionResult>(task =>
            {
                return task.Result;
            });
        }

        #endregion

        #region 流程操作

        /// <summary>
        /// 发起流程
        /// </summary>
        /// <param name="moduleId">模块ID</param>
        /// <param name="id">记录ID</param>
        /// <returns></returns>
        public Task<ActionResult> StartProcessAsync(Guid moduleId, Guid id)
        {
            return Task.Factory.StartNew(() =>
            {
                return new BpmController(Request).StartProcess(moduleId, id);
            }).ContinueWith<ActionResult>(task =>
            {
                return task.Result;
            });
        }

        /// <summary>
        /// 审批流程
        /// </summary>
        /// <param name="toDoTaskId">待办任务ID</param>
        /// <param name="approvalOpinions">处理意见</param>
        /// <param name="workAction">动作</param>
        /// <param name="returnNodeId">退回时退回结点</param>
        /// <param name="directHandler">指派时的被指派人</param>
        /// <returns></returns>
        public Task<ActionResult> ApprovalProcessAsync(Guid toDoTaskId, string approvalOpinions, WorkActionEnum workAction, Guid? returnNodeId = null, Guid? directHandler = null)
        {
            return Task.Factory.StartNew(() =>
            {
                return new BpmController(Request).ApprovalProcess(toDoTaskId, approvalOpinions, workAction, returnNodeId, directHandler);
            }).ContinueWith<ActionResult>(task =>
            {
                return task.Result;
            });
        }

        /// <summary>
        /// 处理待办流程，包括同意、拒绝等操作
        /// </summary>
        /// <param name="toDoTaskId">待办任务ID</param>
        /// <param name="approvalOpinions">处理意见</param>
        /// <param name="flowBtnId">操作按钮ID</param>
        /// <param name="returnNodeId">退回时退回结点</param>
        /// <param name="directHandler">指派时的被指派人</param>
        /// <returns></returns>
        public Task<ActionResult> HandleOpProcessAsync(Guid toDoTaskId, string approvalOpinions, Guid flowBtnId, Guid? returnNodeId = null, Guid? directHandler = null)
        {
            return Task.Factory.StartNew(() =>
            {
                return new BpmController(Request).HandleOpProcess(toDoTaskId, approvalOpinions, flowBtnId, returnNodeId, directHandler);
            }).ContinueWith<ActionResult>(task =>
            {
                return task.Result;
            });
        }

        /// <summary>
        /// 加载回退结点
        /// </summary>
        /// <param name="toDoTaskId">待办ID</param>
        /// <returns></returns>
        public Task<ActionResult> LoadBackNodeAsync(Guid toDoTaskId)
        {
            return Task.Factory.StartNew(() =>
            {
                return new BpmController(Request).LoadBackNode(toDoTaskId);
            }).ContinueWith<ActionResult>(task =>
            {
                return task.Result;
            });
        }

        #endregion
    }
}
